#include <iostream>

// 构建一个最大堆
// 一个数列a,有n个数，以第i个节点为根开始构建最大堆
void MaxHeap(int *a, int n, int i)
{
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    int Max = i;
    if(left < n && a[left] > a[Max])
        Max = left;
    if(right < n && a[right] > a[Max])
        Max = right;
    
    if(Max != i)
    {
        std::swap(a[i], a[Max]);
        MaxHeap(a, n, Max);
    }
}

// 堆排序 O(nlogn)
// 核心思想：找到根，把根放最后面
void HeapSort(int *a, int n)
{
    // 从第一个非叶子节点开始，反向构建最大堆
    // 总数：2^h -1
    // 最后一排（叶子数量）：2^(h-1)
    // 这个公式是由满二叉树推出来的
    for(int i = n / 2 - 1; i >= 0; i--)
    {
        MaxHeap(a, n, i);
    }
    // 将最大值放到后面，对前面的数列再构建堆
    for(int i = n - 1; i >= 0; i--)
    {
        std::swap(a[0], a[i]); // 把根放到数列的最后面
        MaxHeap(a, i, 0);
    }   
}
 
int main()
{
    int a[5] = {5, 6, 1, 3, 9};
    HeapSort(a, 5);

    for(int i = 0; i < 5; i++)
    {
        std::cout<<a[i]<<" ";
    }
    std::cout<<std::endl;

    return 0;
}